﻿using System;
using System.Linq;
using System.Web.UI;

using IdeaNMR.Web.Core;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;
using System.Collections.Generic;

namespace IdeaNMR.Web
{
    [ValidationProperty("Count")]  // Serves for validation control. Count is implemented
    public partial class AuthorList : System.Web.UI.UserControl
    {
        private IdeaNMRdbContainer _Inmr;
        private IdeaNMRdbContainer Inmr
        {
            get
            {
                if (this._Inmr == null) this._Inmr = new IdeaNMRdbContainer();
                return this._Inmr;
            }
        }

        /// <summary>
        /// A CssClass that will be added as prefix to every internal control that has CssClass specified.
        /// </summary>
        public string CssClass { get; set; }

        /// <summary>
        /// Number of selected authors.
        /// </summary>
        public int Count
        {
            get
            {
                return this.Authors.Count;
            }
        }

        /// <summary>
        /// A list of Versions to Display
        /// </summary>
        public List<NumberedAuthor> Authors
        {
            get
            {
                return (List<NumberedAuthor>)ViewState["Authors"];
            }
            set
            { ViewState["Authors"] = value; }
        }

        protected void RemoveAuthorButtonCommand(object sender, CommandEventArgs e)
        {
            if (e.CommandName != "RemoveAuthorCommand") return;

            string username = e.CommandArgument.ToString();

            NumberedAuthor tA = (from na in this.Authors
                                 where na.User.Username == username
                                 select na).Single();
            this.Authors.Remove(tA);

            lvAuthors.DataBind();
        }
        protected void MoveAuthor(object sender, CommandEventArgs e)
        {
            string eName = e.CommandName;
            string tAuth = e.CommandArgument.ToString();

            NumberedAuthor nA = this.Authors.Where(aa => aa.User.Username == tAuth).Single();

            switch (eName)
            {
                case "MoveUpAuthorCommand":
                    if (nA.Index > 0)
                    {
                        NumberedAuthor tA = this.Authors.Where(aa => aa.Index == nA.Index-1).Single();
                        tA.Index += 1;
                        nA.Index -= 1;
                    }
                    break;
                case "MoveDownAuthorCommand":
                    if (nA.Index < this.Authors.Max(aa => aa.Index))
                    {
                        NumberedAuthor tA = this.Authors.Where(aa => aa.Index == nA.Index + 1).Single();
                        tA.Index -= 1;
                        nA.Index += 1;
                    }
                    break;
                default:
                    return;
            }
            lvAuthors.DataBind();
        }


        protected void Page_PreRender(object sender, EventArgs e)
        {
            panMain.CssClass = this.CssClass;

            lvSelectedAuthors.DataSource = this.Authors.OrderBy(a => a.Index);
            lvSelectedAuthors.DataBind();

            lvAuthors.DataSource = this.FilterPrimaryData();
            lvAuthors.DataBind();
        }

        protected string ComposeFullName(User u)
        {
            if (string.IsNullOrEmpty(u.Firstname) || string.IsNullOrEmpty(u.Lastname))
                return "Unnamed (" + u.Username + ")";
            // throw new ArgumentException("First name or last name is null. Must not be.");

            return u.Firstname + (string.IsNullOrEmpty(u.Middlename) ? "" : " " + u.Middlename) + " " + u.Lastname + " (" + u.Username + ")";
        }

        #region Add User
        protected class Item
        {
            public User Obj { get; set; }
        }
        /// <summary>
        /// The search string
        /// </summary>
        /// Default value is string.Empty
        private string[] SearchTerms
        {
            get
            {
                string text = tbSearch.Text;
                if (!string.IsNullOrEmpty(text))
                {
                    return text.ToLowerInvariant().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                }
                else return new string[0];
            }
            set { tbSearch.Text = string.Join(" ", value); }
        }

        protected void SearchButton_Command(object sender, CommandEventArgs e)
        {
            lvAuthors.DataBind();
            tbSearch.Focus();
        }

        protected void AddAuthorButtonCommand(object sender, CommandEventArgs e)
        {
            if (e.CommandName != "AddAuthorCommand") return;

            string username = e.CommandArgument.ToString();

            User oriU = this.PrimaryData.Where(uu => uu.Obj.Username == username).Single().Obj;

            User copyU = new User();
            oriU.CopyTo(copyU, true);

            NumberedAuthor nA = new NumberedAuthor();
            nA.Id = Guid.NewGuid();

            nA.Index = this.Authors.Count > 0
                            ? this.Authors.Max(aa => aa.Index) + 1
                            : 0;
            nA.User = copyU;

            this.Authors.Add(nA);

            lvSelectedAuthors.DataBind();
        }

        /// <summary>
        /// Get all users from ObjectContext
        /// </summary>
        /// <returns></returns>
        protected Item[] GetPrimaryDataFromSource()
        {
            var result = (from User u in this.Inmr.Users
                          select new Item { Obj = u }
                          ).ToArray();
            return result;
        }
        /// <summary>
        /// Filter the users based on search string and already selected users.
        /// </summary>
        /// <returns></returns>
        protected Item[] FilterPrimaryData()
        {
            string alreadySelected = @"^" + string.Join("|^", this.Authors.Select(aa => aa.User.Username).ToArray());
            int numberOfValidAuthors = this.Authors.Where(aa => aa.Index >= 0).Count();

            var result = numberOfValidAuthors > 0
                ? this.PrimaryData.Where(xx => !Regex.IsMatch(xx.Obj.Username, alreadySelected))
                : this.PrimaryData.AsEnumerable();

            if (this.SearchTerms.Length > 0)
            {
                string rPat = @"^" + string.Join("|^", this.SearchTerms).Replace(".", @"\.");
                result = from Item i in result
                         where
                         (Regex.IsMatch(i.Obj.Username, rPat)) ||
                         (!string.IsNullOrEmpty(i.Obj.Firstname) && Regex.IsMatch(i.Obj.Firstname, rPat)) ||
                         (!string.IsNullOrEmpty(i.Obj.Lastname) && Regex.IsMatch(i.Obj.Lastname, rPat))
                         select i;
            }
            return result.ToArray();
        }
        protected Item[] PrimaryData
        {
            get
            {
                if (this._PrimaryData == null)
                    this._PrimaryData = GetPrimaryDataFromSource();
                return this._PrimaryData;
            }
        }
        private Item[] _PrimaryData;

        #endregion
    }
}